import proto from "../../proto/proto";
import { RoomMgr } from "./RoomMgr";
import { ClientServer, InnerMsg } from "../../socket/ClientServer";
import { ClientConnection, ConnectCloseReason } from "../../socket/connection/ClientConnection";
import { G2L_Check_Room, G2L_Match_Room, InnerProtocol, L2G_Check_Room, L2G_Match_Room } from "../../proto/innerMsg";
import { Protocol } from "../../proto/msg";
import { dbFunc } from "../../database/DateBaseFunc";

/**
 * game服务器
 */
export class GameServer extends ClientServer {
    roomMgr: RoomMgr = new RoomMgr();

    /**
     * 连接断开回调
     * @param connection 
     * @param reason 
     */
    onClose(connection: ClientConnection, reason: ConnectCloseReason): void {
        //成功进入房间的链接，是这两个原因断开的链接才是掉线
        if (connection.userId && (reason == ConnectCloseReason.offline || reason == ConnectCloseReason.heartTimeOut)) {
            this.onUserOffline(connection.userId)
        }
    }

    /**
     * 消息回调(处理通用消息)
     * @param connection 
     * @param cmd 
     * @param unit8Array 
     */
    onMsg(connection: ClientConnection, cmd: number, reqWrap: proto.ReqWrap, reqData: any): void {
        switch (cmd) {
            case Protocol.GAME_USER_ENTER_ROOM:
                this.onEnterRoom(connection, cmd, reqWrap, reqData)
                break
            case Protocol.GAME_USER_LEAVE_ROOM:
                this.onUserLeave(connection, cmd, reqWrap, reqData)
                break
            case Protocol.GAME_USER_READY:
                this.onUserReady(connection, cmd, reqWrap, reqData)
                break
            default:
                this.roomMgr.onMsg(connection.userId, cmd, reqWrap, reqData);
        }
    }

    /**
     * 接收内部消息
     * @param cmd 
     * @param data 
     * @param reply
     */
    onInnerMsg(cmd: number, data: InnerMsg, reply: (body?: any) => void): void {
        switch (cmd) {
            case InnerProtocol.CHECK_ROOM:
                {
                    const body = data.body as L2G_Check_Room;
                    const returnData = new G2L_Check_Room()
                    const room = this.roomMgr.getRoomByUserId(body.userId)
                    if (room) {
                        returnData.roomId = room.roomId;
                        returnData.kindId = room.kindId;
                    }
                    reply(returnData);
                }
                break;
            case InnerProtocol.MATCH_ROOM:
                {
                    const body = data.body as L2G_Match_Room
                    const returnData = new G2L_Match_Room()
                    let room = this.roomMgr.getRoomByUserId(body.userId)
                    if (!room) {
                        // 获取可以进入的房间
                        room = this.roomMgr.getCanEnterRoom(body.kindId)
                        // 添加玩家
                        room.addPlayer(body.userId)
                    }
                    console.log(`玩家${body.userId}--kindId:${body.kindId}---房间:${room.roomId}`)
                    returnData.roomId = room.roomId
                    reply(returnData);
                }
                break;

        }
    }

    /**
     * 接收内部推送消息
     * @param cmd 
     * @param data 
     */
    onPushInnerMsg(cmd: number, data: InnerMsg): void {

    }



    /**
     * 进入房间
     */
    async onEnterRoom(connection: ClientConnection, cmd: number, reqWrap: proto.ReqWrap, reqData: any) {
        //玩家进入房间
        const data = reqData as proto.User
        const userId = data.userId;

        const room = this.roomMgr.getRoomByUserId(userId);
        if (!room) {
            console.warn(`异常-------onEnterRoom:${userId}`);
            return
        } 

        const result = await dbFunc.getRoomUserInfos(room.roomId)
        if (result.errorcode != 0) {
            console.log(`获取房间玩家玩家信息失败:${room.roomId}`);
            return
        }

        console.log(`玩家进入房间---userid:${userId},kindid:${room.kindId}`);

        //设置连接id
        connection.userId = userId;

        //检查连接,关闭被挤号玩家
        const userOtherConnections = this.getUserOnlineConnections(connection);
        userOtherConnections.forEach(otherConnection => {
            otherConnection.pushData(Protocol.PUSH_LOGIN_OTHER)
            this.deleteConnection(otherConnection, ConnectCloseReason.squeezed, 5)
        })

        //玩家上线
        room.setOnline(userId, connection)
        //设置房间内玩家昵称
        result.userinfos.forEach(userInfo => {
            const player = room.getPlayer(userInfo.userid as number);
            if (player) {
                player.setNickname(userInfo.nickname)
            }
        })

        //进入房间成功
        connection.sendData(cmd, reqWrap, proto.CODE.SUCCESS);

        //广播房间状态
        room.broadcastRoomState()
        //通知玩家房间内的玩家信息
        room.broadcastRoomUserInfos();
    }

    /**
     * 玩家离开 
     */
    async onUserLeave(connection: ClientConnection, cmd: number, reqWrap: proto.ReqWrap, reqData: any) {
        const userId = connection.userId;
        const room = this.roomMgr.getRoomByUserId(userId);
        if (!room) {
            console.warn(`异常-------onUserLeave:${userId}`);
            return
        }

        //玩家离开
        await dbFunc.userLeave(userId)
        //广播玩家离开
        room.broadcast(Protocol.PUSH_ROOM_USER_LEAVE, { userId });
        //从房间移除玩家
        room.removePlayer(userId)
        //从server连接列表删除(不是立即清理)
        this.deleteConnection(connection, ConnectCloseReason.leave, 5)
        console.warn(`玩家退出房间:${connection.userId}`);
    }

    /**
     * 玩家掉线
     * @param userId 
     */
    onUserOffline(userId: number) {
        console.log(`玩家掉线:${userId}`);
        const room = this.roomMgr.getRoomByUserId(userId);
        if (!room) {
            console.warn(`异常-------onUserLeave:${userId}`);
            return
        }
        //设置玩家掉线
        room.setOffLine(userId)
        //通知玩家房间内的玩家信息
        room.broadcastRoomUserInfos();
    }

    /**
     * 玩家准备
     */
    onUserReady(connection: ClientConnection, cmd: number, reqWrap: proto.ReqWrap, reqData: any) {
        const userId = connection.userId;
        const room = this.roomMgr.getRoomByUserId(userId);
        if (!room) {
            console.warn(`异常-------onUserLeave:${userId}`);
            return
        }

        //设置玩家准备状态
        if (room.getPlayerState(userId) == proto.PlayerStateEnum.SIT) {
            console.log(`玩家准备:${userId}`);
            //设置玩家状态
            room.setPlayerState(userId, proto.PlayerStateEnum.READY)
            //回复玩家准备
            connection.sendData(cmd, reqWrap, proto.CODE.SUCCESS);
            //通知玩家房间内的房间玩家信息
            room.broadcastRoomUserInfos()
        }

        // 如果房间满足开始条件,则房间开始
        this.roomMgr.startRoom(room.roomId)
    }
}